#include "commands.h"

AddObjectCommand::AddObjectCommand(GLWidget *_glWidget, int _objectType, QUndoCommand *parent):QUndoCommand(parent)
{
    glWidget = _glWidget;
    if (_objectType==CELL_SPHERE) {
        //isn't allocating a new CellObject redundant because addObject returns a pointer to a new CellObject?
        //object = new CellObject();
        object = glWidget->addSphere();
    } else if (_objectType==CELL_CYLINDER) {
        //object = new CellObject();
        object = glWidget->addCylinder();
    } else if (_objectType==CELL_CUBE) {
        //object = new CellObject();
        object = glWidget->addCube();
    } else if (_objectType==CELL_OPENCYLINDER) {
        //object = new CellObject();
        object = glWidget->addOpenCylinder();
    } else if(_objectType==CELL_PLANE) {
        //object = new CellObject();
        object = glWidget->addPlane();
    } else if(_objectType==CELL_LINE) {
        //object = new CellObject();
        object = glWidget->addLine();
    }
}

AddObjectCommand::~AddObjectCommand()
{
    //cout << "enter ~AddObjectCommand()" << endl;
    delete object;
    //cout << "exit ~AddObjectCommand()" << endl;
}

void AddObjectCommand::undo()
{
    //delete the last thing that was added
    glWidget->deleteObject(glWidget->getObjects().size()-1);
    //update the GL window
    glWidget->updateGL();
}

void AddObjectCommand::redo()
{
    glWidget->addObject(object);
    glWidget->updateGL();
}

DeleteObjectCommand::DeleteObjectCommand(GLWidget *_glWidget, int _index, QUndoCommand *parent):QUndoCommand(parent)
{
    glWidget = _glWidget;
    index = _index;
    object = new CellObject();
    object = glWidget->getObjects().at(index-2);
    //cout << "commands1: " << glWidget->getSelectObject() << endl;
    glWidget->setSelectObject(-1);
    //cout << "commands1: " << glWidget->getSelectObject() << endl;
}

DeleteObjectCommand::~DeleteObjectCommand()
{
    //come back and do this later
}

void DeleteObjectCommand::undo()
{
    glWidget->addObject(object, index);
    //cout << "commands2: " << glWidget->getSelectObject() << endl;
    glWidget->setSelectObject(index);
    //cout << "commands2: " << glWidget->getSelectObject() << endl;
    glWidget->setInputType();
    glWidget->updateGL();
}

void DeleteObjectCommand::redo()
{
    glWidget->deleteObject(index-2);
    //cout << "commands3: " << glWidget->getSelectObject() << endl;
    glWidget->setSelectObject(-1);
    //cout << "commands3: " << glWidget->getSelectObject() << endl;
    glWidget->updateGL();
}



UnionCommand::UnionCommand(GLWidget *_glWidget, int _firstIndex, int _secondIndex, QUndoCommand *parent):QUndoCommand(parent)
{
    glWidget = _glWidget;
    firstIndex = _firstIndex;
    secondIndex = _secondIndex;
    firstObject = new CellObject();
    secondObject = new CellObject();
    resultObject = new CellObject();
    firstObject = glWidget->getObjects().at(firstIndex-2);
    secondObject = glWidget->getObjects().at(secondIndex-2);
    glWidget->Union(firstObject, secondObject, resultObject);
}

UnionCommand::~UnionCommand()
{
    //cout << "UnionCommand::~UnionCommand()" << endl;
    delete resultObject;
}

void UnionCommand::undo()
{
    //delete the last object that was added (the result of a union)
    glWidget->deleteObject(glWidget->getObjects().size()-1);

    if (firstIndex<secondIndex) {
        glWidget->addObject(firstObject, firstIndex-2);
        glWidget->addObject(secondObject, secondIndex-2);
    } else {
        glWidget->addObject(secondObject, secondIndex-2);
        glWidget->addObject(firstObject, firstIndex-2);
    }
    //cout << "commands4: " << glWidget->getSelectObject() << endl;
    glWidget->setSelectObject(firstIndex);
    //cout << "commands4: " << glWidget->getSelectObject() << endl;
    glWidget->setSecondSelectObject(secondIndex);
    glWidget->setInputType();
    glWidget->updateGL();
}

void UnionCommand::redo()
{
    //delete the two selected objects
    if (firstIndex<secondIndex) {
        glWidget->deleteObject(firstIndex-2);
        glWidget->deleteObject(secondIndex-3);
    } else {
        glWidget->deleteObject(firstIndex-2);
        glWidget->deleteObject(secondIndex-2);
    }
    //add the resulting object
    glWidget->addObject(resultObject);
    //select the resulting object
    //cout << "commands5: " << glWidget->getSelectObject() << endl;
    glWidget->setSelectObject(glWidget->getObjects().size()-1+2);
    //cout << "commands5: " << glWidget->getSelectObject() << endl;
    //clear the second selected object
    glWidget->setSecondSelectObject(-1);
    //update the input type
    glWidget->setInputType();
    //update the gl window
    glWidget->updateGL();
}

IntersectCommand::IntersectCommand(GLWidget *_glWidget, int _firstIndex, int _secondIndex, QUndoCommand *parent):QUndoCommand(parent)
{
    glWidget = _glWidget;
    firstIndex = _firstIndex;
    secondIndex = _secondIndex;
    firstObject = new CellObject();
    secondObject = new CellObject();
    resultObject = new CellObject();
    firstObject = glWidget->getObjects().at(firstIndex-2);
    secondObject = glWidget->getObjects().at(secondIndex-2);
    glWidget->Intersect(firstObject, secondObject, resultObject);
}

IntersectCommand::~IntersectCommand()
{
    //cout << "IntersectCommand::~IntersectCommand()" << endl;
    delete resultObject;
}

void IntersectCommand::undo()
{
    glWidget->deleteObject(glWidget->getObjects().size()-1);
    if (firstIndex<secondIndex) {
        glWidget->addObject(firstObject, firstIndex-2);
        glWidget->addObject(secondObject, secondIndex-2);
    } else {
        glWidget->addObject(secondObject, secondIndex-2);
        glWidget->addObject(firstObject, firstIndex-2);
    }
    //cout << "commands6: " << glWidget->getSelectObject() << endl;
    glWidget->setSelectObject(firstIndex);
    //cout << "commands6: " << glWidget->getSelectObject() << endl;
    glWidget->setSecondSelectObject(secondIndex);
    glWidget->setInputType();
    glWidget->updateGL();
}

void IntersectCommand::redo()
{
    if (firstIndex<secondIndex) {
        glWidget->deleteObject(firstIndex-2);
        glWidget->deleteObject(secondIndex-3);
    } else {
        glWidget->deleteObject(firstIndex-2);
        glWidget->deleteObject(secondIndex-2);
    }
    glWidget->addObject(resultObject);
    //cout << "commands7: " << glWidget->getSelectObject() << endl;
    glWidget->setSelectObject(glWidget->getObjects().size()-1+2);
    //cout << "commands7: " << glWidget->getSelectObject() << endl;
    glWidget->setSecondSelectObject(-1);
    glWidget->setInputType();
    glWidget->updateGL();
}

SubtractCommand::SubtractCommand(GLWidget *_glWidget, int _firstIndex, int _secondIndex, QUndoCommand *parent):QUndoCommand(parent)
{
    glWidget = _glWidget;
    firstIndex = _firstIndex;
    secondIndex = _secondIndex;
    firstObject = new CellObject();
    secondObject = new CellObject();
    resultObject = new CellObject();
    firstObject = glWidget->getObjects().at(firstIndex-2);
    secondObject = glWidget->getObjects().at(secondIndex-2);
    glWidget->Subtract(firstObject, secondObject, resultObject);
}

SubtractCommand::~SubtractCommand()
{
    //cout << "SubtractCommand::~SubtractCommand()" << endl;
    delete resultObject;
}

void SubtractCommand::undo()
{
    glWidget->deleteObject(glWidget->getObjects().size()-1);
    if (firstIndex<secondIndex) {
        glWidget->addObject(firstObject, firstIndex-2);
        glWidget->addObject(secondObject, secondIndex-2);
    } else {
        glWidget->addObject(secondObject, secondIndex-2);
        glWidget->addObject(firstObject, firstIndex-2);
    }
    //cout << "commands8: " << glWidget->getSelectObject() << endl;
    glWidget->setSelectObject(firstIndex);
    //cout << "commands8: " << glWidget->getSelectObject() << endl;
    glWidget->setSecondSelectObject(secondIndex);
    glWidget->setInputType();
    glWidget->updateGL();
}

void SubtractCommand::redo()
{
    if (firstIndex<secondIndex) {
        glWidget->deleteObject(firstIndex-2);
        glWidget->deleteObject(secondIndex-3);
    } else {
        glWidget->deleteObject(firstIndex-2);
        glWidget->deleteObject(secondIndex-2);
    }
    glWidget->addObject(resultObject);
    //cout << "commands9: " << glWidget->getSelectObject() << endl;
    glWidget->setSelectObject(glWidget->getObjects().size()-1+2);
    //cout << "commands9: " << glWidget->getSelectObject() << endl;
    glWidget->setSecondSelectObject(-1);
    glWidget->setInputType();
    glWidget->updateGL();
}

TranslateCommand::TranslateCommand(GLWidget *_glWidget, double _oldX, double _oldY, double _oldZ,
                                   double _newX, double _newY, double _newZ, int _index, QUndoCommand *parent):QUndoCommand(parent)
{
    glWidget = _glWidget;
    oldX = _oldX;
    oldY = _oldY;
    oldZ = _oldZ;
    newX = _newX;
    newY = _newY;
    newZ = _newZ;
    index = _index;
}

TranslateCommand::~TranslateCommand()
{
    //cout << "TranslateCommand::~TranslateCommand()" << endl;
}

void TranslateCommand::undo()
{
    //cout << "commands10: " << glWidget->getSelectObject() << endl;
    glWidget->setSelectObject(index);
    //cout << "commands10: " << glWidget->getSelectObject() << endl;
    glWidget->setTranslateX(oldX);
    glWidget->setTranslateY(oldY);
    glWidget->setTranslateZ(oldZ);
    glWidget->setInputType();
    glWidget->updateGL();
}

void TranslateCommand::redo()
{
    //cout << "commands11: " << glWidget->getSelectObject() << endl;
    //cout << "empty? " << glWidget->emptyScene() << endl;
    //if(!glWidget->emptyScene())
        glWidget->setSelectObject(index);
    //cout << "commands11: " << glWidget->getSelectObject() << endl;
    glWidget->setTranslateX(newX);
    glWidget->setTranslateY(newY);
    glWidget->setTranslateZ(newZ);
    glWidget->setInputType();
    glWidget->updateGL();
}

void TranslateCommand::setNew(double _newX, double _newY, double _newZ)
{
    newX = _newX;
    newY = _newY;
    newZ = _newZ;
}

RotateCommand::RotateCommand(GLWidget *_glWidget, double _oldX, double _oldY, double _oldZ,
                                   double _newX, double _newY, double _newZ, int _index, QUndoCommand *parent):QUndoCommand(parent)
{
    glWidget = _glWidget;
    oldX = _oldX;
    oldY = _oldY;
    oldZ = _oldZ;
    newX = _newX;
    newY = _newY;
    newZ = _newZ;
    index = _index;
}

RotateCommand::~RotateCommand()
{
    //cout << "enter ~RotateCommand()" << endl;
    //cout << "exit ~RotateCommand()" << endl;
}

void RotateCommand::undo()
{
    //cout << "commands12: " << glWidget->getSelectObject() << endl;
    glWidget->setSelectObject(index);
    //cout << "commands12: " << glWidget->getSelectObject() << endl;
    glWidget->setRotateX(oldX);
    glWidget->setRotateY(oldY);
    glWidget->setRotateZ(oldZ);
    glWidget->setInputType();
    glWidget->updateGL();
}

void RotateCommand::redo()
{
    //cout << "commands13: " << glWidget->getSelectObject() << endl;
    glWidget->setSelectObject(index);
    //cout << "commands13: " << glWidget->getSelectObject() << endl;
    glWidget->setRotateX(newX);
    glWidget->setRotateY(newY);
    glWidget->setRotateZ(newZ);
    glWidget->setInputType();
    glWidget->updateGL();
}

void RotateCommand::setNew(double _newX, double _newY, double _newZ)
{
    newX = _newX;
    newY = _newY;
    newZ = _newZ;
}

ScaleCommand::ScaleCommand(GLWidget *_glWidget, double _oldX, double _oldY, double _oldZ,
                                   double _newX, double _newY, double _newZ, int _index, QUndoCommand *parent):QUndoCommand(parent)
{
    glWidget = _glWidget;
    oldX = _oldX;
    oldY = _oldY;
    oldZ = _oldZ;
    newX = _newX;
    newY = _newY;
    newZ = _newZ;
    index = _index;
}

ScaleCommand::~ScaleCommand()
{
    //cout << "ScaleCommand::~ScaleCommand()" << endl;
}

void ScaleCommand::undo()
{
    //cout << "commands17: " << glWidget->getSelectObject() << endl;
    glWidget->setSelectObject(index);
    //cout << "commands17: " << glWidget->getSelectObject() << endl;
    glWidget->setScaleX(oldX);
    glWidget->setScaleY(oldY);
    glWidget->setScaleZ(oldZ);
    glWidget->setInputType();
    glWidget->updateGL();
}

void ScaleCommand::redo()
{
    //cout << "commands14: " << glWidget->getSelectObject() << endl;
    glWidget->setSelectObject(index);
    //cout << "commands14: " << glWidget->getSelectObject() << endl;
    glWidget->setScaleX(newX);
    glWidget->setScaleY(newY);
    glWidget->setScaleZ(newZ);
    glWidget->setInputType();
    glWidget->updateGL();
}

void ScaleCommand::setNew(double _newX, double _newY, double _newZ)
{
    newX = _newX;
    newY = _newY;
    newZ = _newZ;
}

SphereInputCommand::SphereInputCommand(GLWidget *_glWidget, CellObject *_obj,
                                       double _oldRadius, int _oldHeightSeg, int _oldAxisSeg,
                                       double _newRadius, int _newHeightSeg, int _newAxisSeg, QUndoCommand *parent):QUndoCommand(parent)
{
    glWidget = _glWidget;
    object = new CellObject();
    object = _obj;
    oldRadius = _oldRadius;
    oldHeightSeg = _oldHeightSeg;
    oldAxisSeg = _oldAxisSeg;
    newRadius = _newRadius;
    newHeightSeg = _newHeightSeg;
    newAxisSeg = _newAxisSeg;
}

SphereInputCommand::~SphereInputCommand()
{
    //cout << "SphereInputCommand::~SphereInputCommand()" << endl;
}

void SphereInputCommand::undo()
{
    object->buildSphere(oldRadius, oldHeightSeg, oldAxisSeg);
    glWidget->updateGL();
}

void SphereInputCommand::redo()
{
    object->buildSphere(newRadius, newHeightSeg, newAxisSeg);
    glWidget->updateGL();
}

CylinderInputCommand::CylinderInputCommand(GLWidget *_glWidget, CellObject *_obj,
                                           double _oldRadius, double _oldHeight, int _oldHeightSeg, int _oldAxisSeg,
                                           double _newRadius, double _newHeight, int _newHeightSeg, int _newAxisSeg, int _type, QUndoCommand *parent):QUndoCommand(parent)
{
    glWidget = _glWidget;
    object = new CellObject();
    object = _obj;
    oldRadius = _oldRadius;
    oldHeight = _oldHeight;
    oldHeightSeg = _oldHeightSeg;
    oldAxisSeg = _oldAxisSeg;
    newRadius = _newRadius;
    newHeight = _newHeight;
    newHeightSeg = _newHeightSeg;
    newAxisSeg = _newAxisSeg;
    type = _type;
}

CylinderInputCommand::~CylinderInputCommand()
{
    //cout << "CylinderInputCommand::~CylinderInputCommand()" << endl;
}

void CylinderInputCommand::undo()
{
    if (type==CELL_CYLINDER)
        object->buildCylinder(oldRadius, oldHeight, oldAxisSeg, oldHeightSeg);
    else if (type==CELL_OPENCYLINDER)
        object->buildOpenCylinder(oldRadius, oldHeight, oldAxisSeg, oldHeightSeg);
    glWidget->updateGL();
}

void CylinderInputCommand::redo()
{
    if (type==CELL_CYLINDER)
        object->buildCylinder(newRadius, newHeight, newAxisSeg, newHeightSeg);
    else if (type==CELL_OPENCYLINDER)
        object->buildOpenCylinder(newRadius, newHeight, newAxisSeg, newHeightSeg);
    glWidget->updateGL();
}

CubeInputCommand::CubeInputCommand(GLWidget *_glWidget, CellObject *_obj,
                                   double _oldWidth, double _oldHeight, double _oldDepth,
                                   int _oldWidthSeg, int _oldHeightSeg, int _oldDepthSeg,
                                   double _newWidth, double _newHeight, double _newDepth,
                                   int _newWidthSeg, int _newHeightSeg, int _newDepthSeg, QUndoCommand *parent):QUndoCommand(parent)
{
    glWidget = _glWidget;
    object = new CellObject();
    object = _obj;
    oldWidth = _oldWidth;
    oldHeight = _oldHeight;
    oldDepth = _oldDepth;
    oldWidthSeg = _oldWidthSeg;
    oldHeightSeg = _oldHeightSeg;
    oldDepthSeg = _oldDepthSeg;
    newWidth = _newWidth;
    newHeight = _newHeight;
    newDepth = _newDepth;
    newWidthSeg = _newWidthSeg;
    newHeightSeg = _newHeightSeg;
    newDepthSeg = _newDepthSeg;
}

CubeInputCommand::~CubeInputCommand()
{
    //cout << "CubeInputCommand::~CubeInputCommand()" << endl;
}

void CubeInputCommand::undo()
{
    object->buildCube(oldWidth, oldHeight, oldDepth, oldWidthSeg, oldHeightSeg, oldDepthSeg);
    glWidget->updateGL();
}

void CubeInputCommand::redo()
{
    object->buildCube(newWidth, newHeight, newDepth, newWidthSeg, newHeightSeg, newDepthSeg);
    glWidget->updateGL();
}

SelectObjectCommand::SelectObjectCommand(GLWidget *_glWidget, int _lastSelectObject, QUndoCommand *parent):QUndoCommand(parent)
{
    glWidget = _glWidget;
    lastSelectObject = _lastSelectObject;
}

SelectObjectCommand::~SelectObjectCommand()
{
    //cout << "SelectObjectCommand::~SelectObjectCommand()" << endl;
    //cout << "enter and exit ~SelectObjectCommand()" << endl;
}

void SelectObjectCommand::setRecSelectObject(int s)
{
    recSelectObject = s;
}

bool SelectObjectCommand::isSelectChanged()
{
    return lastSelectObject != recSelectObject;
}

void SelectObjectCommand::undo()
{
    //cout << "commands15: " << glWidget->getSelectObject() << endl;
    glWidget->setSelectObject(lastSelectObject);
    //cout << "commands15: " << glWidget->getSelectObject() << endl;
    glWidget->setInputType();
    glWidget->updateGL();
}

void SelectObjectCommand::redo()
{
    //cout << "commands16: " << glWidget->getSelectObject() << endl;
    glWidget->setSelectObject(recSelectObject);
    //cout << "commands16: " << glWidget->getSelectObject() << endl;
    glWidget->setInputType();
    glWidget->updateGL();
}

MeshChangedCommand::MeshChangedCommand(GLWidget *_glWidget, CellObject *_unchangedObject, int _index, QUndoCommand *parent):QUndoCommand(parent)
{
    glWidget = _glWidget;
    unchangedObject = new CellObject();
    changedObject = new CellObject();
    index = _index;
    unchangedObject = _unchangedObject;
    changedObject = _unchangedObject->clone();
    if (index==0) {
        glWidget->setGlandular(changedObject);
    } else if (index>1) {
        glWidget->setObject(changedObject, index-2);
    }
}

MeshChangedCommand::~MeshChangedCommand()
{
    //cout << "MeshChangedCommand::~MeshChangedCommand()" << endl;
    delete changedObject;
}

void MeshChangedCommand::undo()
{
    if (index==0) {
        glWidget->setGlandular(unchangedObject);
    } else if (index>1) {
        glWidget->setObject(unchangedObject, index-2);
    }
    glWidget->updateGL();
}

void MeshChangedCommand::redo()
{
    if (index==0) {
        glWidget->setGlandular(changedObject);
    } else if (index>1) {
        glWidget->setObject(changedObject, index-2);
    }
    glWidget->updateGL();
}
